package cn.yeziji.common;

import cn.yeziji.enums.GCommonEnums;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Objects;
import java.util.StringJoiner;

@Data
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GResult {
  private int code;
  private String msg;
  private Object data;

  private interface init {
    GResult create(GCommonEnums enums, Object data);

    GResult build();
  }

  public static GResultInit init() {
    return new GResultInit();
  }

  private GResult(GResultInit init) {
    this.code = init.code;
    this.msg = init.msg;
    this.data = init.data;
  }

  public static class GResultInit implements init, Serializable {
    private Integer code;
    private String msg;
    private Object data;

    public GResultInit code(Integer code) {
      this.code = code;
      return this;
    }

    public GResultInit msg(String msg) {
      this.msg = msg;
      return this;
    }

    public GResultInit data(Object data) {
      if (Objects.nonNull(data)) this.data = data;
      return this;
    }

    @Override
    public GResult create(GCommonEnums enums, Object data) {
      this.code = enums.getCode();
      this.msg = enums.getMsg();
      if (Objects.nonNull(data)) this.data = data;
      return new GResult(this);
    }

    @Override
    public GResult build() {
      GResult result = new GResult();
      if (Objects.nonNull(this.code)) result.code = this.code;
      if (Objects.nonNull(this.data)) result.data = this.data;
      if (Objects.nonNull(this.msg)) result.msg = this.msg;
      return result;
    }
  }

  public GResult OK(Object data) {
    this.code = GCommonEnums.SUCCESS.getCode();
    this.msg = GCommonEnums.SUCCESS.getMsg();
    this.data = data;
    return this;
  }

  @SneakyThrows
  @Override
  public String toString() {
    Class<?> clazz = this.getClass();
    StringJoiner sj =
        new StringJoiner(",", clazz.getName() + "=(", ")").setEmptyValue("No Parameters");
    StringBuilder sb = new StringBuilder();
    Field[] declaredFields = clazz.getDeclaredFields();
    for (Field field : declaredFields) {
      field.setAccessible(true);
      Object value = field.get(this);
      if (Objects.nonNull(value)) {
        String name = field.getName();
        sj.add(sb.append(name).append("=").append(value).append(" ").toString());
        sb.delete(0, sb.length());
      }
    }
    return sj.toString();
  }
}
